package cn.iocoder.yudao.module.system.service.lottery;

import cn.iocoder.yudao.framework.common.exception.ErrorCode;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.system.controller.admin.lottery.vo.LotteryRespVO;
import cn.iocoder.yudao.module.system.controller.admin.lottery.vo.LotteryRecordRespVO;
import cn.iocoder.yudao.module.system.dal.dataobject.lottery.LotteryConfigDO;
import cn.iocoder.yudao.module.system.dal.dataobject.lottery.LotteryRecordDO;
import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
import cn.iocoder.yudao.module.system.dal.dataobject.user.UserAssetsDO;
import cn.iocoder.yudao.module.system.dal.mysql.lottery.LotteryConfigMapper;
import cn.iocoder.yudao.module.system.dal.mysql.lottery.LotteryRecordMapper;
import cn.iocoder.yudao.module.system.dal.mysql.user.AdminUserMapper;
import cn.iocoder.yudao.module.system.enums.lottery.LotteryPrizeTypeEnum;
import cn.iocoder.yudao.module.system.service.user.UserAssetsService;
import cn.iocoder.yudao.module.system.service.task.UserTaskService;
import cn.iocoder.yudao.module.system.controller.admin.user.vo.user.UserAssetsSaveReqVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.Arrays;
import java.util.List;
import java.util.Random;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;

/**
 * 抽奖 Service 实现类
 *
 * @author 芋道源码
 */
@Service
@Validated
@Slf4j
public class LotteryServiceImpl implements LotteryService {

    @Resource
    private LotteryRecordMapper lotteryRecordMapper;

    @Resource
    private LotteryConfigMapper lotteryConfigMapper;

    @Resource
    private UserAssetsService userAssetsService;

    @Resource
    private UserTaskService userTaskService;

    @Resource
    private AdminUserMapper adminUserMapper;

    private static final String CONFIG_KEY_DAILY_LOTTERY_LIMIT = "daily_lottery_limit";
    private static final String CONFIG_KEY_PROFESSIONAL_REPORT_DAILY_LIMIT = "professional_report_daily_limit";

    // 有专业版报告库存时的概率配置键
    private static final String CONFIG_KEY_FULL_PACKAGE_PROB_WITH_STOCK = "full_package_prob_with_stock";
    private static final String CONFIG_KEY_PROFESSIONAL_REPORT_PROB_WITH_STOCK = "professional_report_prob_with_stock";
    private static final String CONFIG_KEY_BASIC_REPORT_PROB_WITH_STOCK = "basic_report_prob_with_stock";
    private static final String CONFIG_KEY_ASK_COUNT_PROB_WITH_STOCK = "ask_count_prob_with_stock";
    private static final String CONFIG_KEY_CONTENT_MEMBER_PROB_WITH_STOCK = "content_member_prob_with_stock";
    private static final String CONFIG_KEY_NO_PRIZE_PROB_WITH_STOCK = "no_prize_prob_with_stock";

    // 无专业版报告库存时的概率配置键
    private static final String CONFIG_KEY_FULL_PACKAGE_PROB_NO_STOCK = "full_package_prob_no_stock";
    private static final String CONFIG_KEY_BASIC_REPORT_PROB_NO_STOCK = "basic_report_prob_no_stock";
    private static final String CONFIG_KEY_ASK_COUNT_PROB_NO_STOCK = "ask_count_prob_no_stock";
    private static final String CONFIG_KEY_CONTENT_MEMBER_PROB_NO_STOCK = "content_member_prob_no_stock";
    private static final String CONFIG_KEY_NO_PRIZE_PROB_NO_STOCK = "no_prize_prob_no_stock";

    private static final int DEFAULT_DAILY_LOTTERY_LIMIT = 1; // 每日抽奖次数限制
    private static final int DEFAULT_PROFESSIONAL_REPORT_DAILY_LIMIT = 100; // 专业版报告每日限量

    // 默认概率值（有专业版报告库存时）
    private static final int DEFAULT_FULL_PACKAGE_PROB_WITH_STOCK = 2;
    private static final int DEFAULT_PROFESSIONAL_REPORT_PROB_WITH_STOCK = 28;
    private static final int DEFAULT_BASIC_REPORT_PROB_WITH_STOCK = 25;
    private static final int DEFAULT_ASK_COUNT_PROB_WITH_STOCK = 22;
    private static final int DEFAULT_CONTENT_MEMBER_PROB_WITH_STOCK = 22;
    private static final int DEFAULT_NO_PRIZE_PROB_WITH_STOCK = 1;

    // 默认概率值（无专业版报告库存时）
    private static final int DEFAULT_FULL_PACKAGE_PROB_NO_STOCK = 1;
    private static final int DEFAULT_BASIC_REPORT_PROB_NO_STOCK = 33;
    private static final int DEFAULT_ASK_COUNT_PROB_NO_STOCK = 33;
    private static final int DEFAULT_CONTENT_MEMBER_PROB_NO_STOCK = 32;
    private static final int DEFAULT_NO_PRIZE_PROB_NO_STOCK = 1;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public LotteryRespVO drawLottery(Long userId) {
        // 1. 检查用户是否能抽奖
        if (!canDrawLottery(userId)) {
            throw exception(new ErrorCode(400, "今日抽奖次数已用完"));
        }

        // 2. 执行抽奖逻辑
        LotteryPrizeTypeEnum prizeType = executeLottery(userId);

        // 3. 记录抽奖结果
        LotteryRecordDO record = LotteryRecordDO.builder()
                .userId(userId)
                .prizeType(prizeType.getType())
                .prizeName(prizeType.getName())
                .lotteryTime(LocalDateTime.now())
                .awarded(false)
                .build();
        lotteryRecordMapper.insert(record);

        // 4. 发放奖品
        if (prizeType != LotteryPrizeTypeEnum.NO_PRIZE) {
            awardPrize(userId, prizeType, record.getId());
        }

        // 5. 构造返回结果
        LotteryRespVO result = new LotteryRespVO();
        result.setRecordId(record.getId());
        result.setPrizeType(prizeType.getType());
        result.setPrizeName(prizeType.getName());
        result.setIsWin(prizeType != LotteryPrizeTypeEnum.NO_PRIZE);
        result.setLotteryTime(record.getLotteryTime());
        if (prizeType == LotteryPrizeTypeEnum.NO_PRIZE) {
            result.setMessage("很遗憾，未中奖，明天再来试试吧！");
        } else if (prizeType == LotteryPrizeTypeEnum.FULL_PACKAGE) {
            boolean hasProfessionalReportStock = checkProfessionalReportStock();
            result.setMessage("恭喜您获得" + prizeType.getName() + "！" + getFullPackageDescription(hasProfessionalReportStock));
        } else {
            result.setMessage("恭喜您获得" + prizeType.getName() + "！");
        }

        return result;
    }

    @Override
    public List<LotteryRecordRespVO> getUserLotteryRecords(Long userId) {
        List<LotteryRecordDO> records = lotteryRecordMapper.selectListByUserId(userId);
        return BeanUtils.toBean(records, LotteryRecordRespVO.class);
    }

    @Override
    public boolean canDrawLottery(Long userId) {
        return getRemainingLotteryCount(userId) > 0;
    }

    @Override
    public int getRemainingLotteryCount(Long userId) {
        // 获取每日抽奖次数限制
        int dailyLimit = getDailyLotteryLimit();

        // 获取通过任务获得的额外抽奖次数
        int taskLotteryCount = userTaskService.getTodayTaskLotteryCount(userId);

        // 总的可用抽奖次数 = 基础次数 + 任务获得次数
        int totalAvailableCount = dailyLimit + taskLotteryCount;

        // 获取今日已抽奖次数
        LocalDateTime startOfDay = LocalDateTime.now().with(LocalTime.MIN);
        LocalDateTime endOfDay = LocalDateTime.now().with(LocalTime.MAX);
        Long todayCount = lotteryRecordMapper.countTodayLotteryByUserId(userId, startOfDay, endOfDay);

//        return Math.max(0, totalAvailableCount - todayCount.intValue());
        return Math.max(0, 99);
    }

    /**
     * 执行抽奖逻辑
     */
    private LotteryPrizeTypeEnum executeLottery(Long userId) {
        // 验证概率配置
        validateProbabilityConfig();

        // 获取用户已中过的奖励类型
        List<Integer> wonPrizeTypes = lotteryRecordMapper.selectWonPrizeTypesByUserId(userId);

        // 检查是否所有奖励都已中过
        if (hasWonAllPrizes(wonPrizeTypes)) {
            log.info("用户{}已中过所有奖励，本次抽奖结果为未中奖", userId);
            return LotteryPrizeTypeEnum.NO_PRIZE;
        }

        // 检查专业版报告是否还有库存
        boolean hasProfessionalReportStock = checkProfessionalReportStock();

        Random random = new Random();
        int randomNum = random.nextInt(100) + 1; // 1-100的随机数

        if (hasProfessionalReportStock) {
            // 有专业版报告库存时的概率分布
            return executeLotteryWithStock(randomNum, wonPrizeTypes);
        } else {
            // 没有专业版报告库存时的概率分布
            return executeLotteryNoStock(randomNum, wonPrizeTypes);
        }
    }

    /**
     * 检查用户是否已中过所有奖励
     */
    private boolean hasWonAllPrizes(List<Integer> wonPrizeTypes) {
        // 所有可中奖的奖励类型（排除未中奖）
        List<Integer> allPrizeTypes = Arrays.asList(
                LotteryPrizeTypeEnum.BASIC_REPORT.getType(),
                LotteryPrizeTypeEnum.PROFESSIONAL_REPORT.getType(),
                LotteryPrizeTypeEnum.ASK_COUNT_5.getType(),
                LotteryPrizeTypeEnum.CONTENT_MEMBER_1DAY.getType(),
                LotteryPrizeTypeEnum.FULL_PACKAGE.getType()
        );

        // 检查是否所有奖励类型都已中过
        return wonPrizeTypes.containsAll(allPrizeTypes);
    }

    /**
     * 有专业版报告库存时的抽奖逻辑
     */
    private LotteryPrizeTypeEnum executeLotteryWithStock(int randomNum, List<Integer> wonPrizeTypes) {
        // 获取原始概率配置
        int fullPackageProb = getProbabilityConfig(CONFIG_KEY_FULL_PACKAGE_PROB_WITH_STOCK, DEFAULT_FULL_PACKAGE_PROB_WITH_STOCK);
        int professionalReportProb = getProbabilityConfig(CONFIG_KEY_PROFESSIONAL_REPORT_PROB_WITH_STOCK, DEFAULT_PROFESSIONAL_REPORT_PROB_WITH_STOCK);
        int basicReportProb = getProbabilityConfig(CONFIG_KEY_BASIC_REPORT_PROB_WITH_STOCK, DEFAULT_BASIC_REPORT_PROB_WITH_STOCK);
        int askCountProb = getProbabilityConfig(CONFIG_KEY_ASK_COUNT_PROB_WITH_STOCK, DEFAULT_ASK_COUNT_PROB_WITH_STOCK);
        int contentMemberProb = getProbabilityConfig(CONFIG_KEY_CONTENT_MEMBER_PROB_WITH_STOCK, DEFAULT_CONTENT_MEMBER_PROB_WITH_STOCK);
        int noPrizeProb = getProbabilityConfig(CONFIG_KEY_NO_PRIZE_PROB_WITH_STOCK, DEFAULT_NO_PRIZE_PROB_WITH_STOCK);

        // 排除已中过的奖励，重新分配概率
        int totalExcludedProb = 0;
        if (wonPrizeTypes.contains(LotteryPrizeTypeEnum.FULL_PACKAGE.getType())) {
            totalExcludedProb += fullPackageProb;
            fullPackageProb = 0;
        }
        if (wonPrizeTypes.contains(LotteryPrizeTypeEnum.PROFESSIONAL_REPORT.getType())) {
            totalExcludedProb += professionalReportProb;
            professionalReportProb = 0;
        }
        if (wonPrizeTypes.contains(LotteryPrizeTypeEnum.BASIC_REPORT.getType())) {
            totalExcludedProb += basicReportProb;
            basicReportProb = 0;
        }
        if (wonPrizeTypes.contains(LotteryPrizeTypeEnum.ASK_COUNT_5.getType())) {
            totalExcludedProb += askCountProb;
            askCountProb = 0;
        }
        if (wonPrizeTypes.contains(LotteryPrizeTypeEnum.CONTENT_MEMBER_1DAY.getType())) {
            totalExcludedProb += contentMemberProb;
            contentMemberProb = 0;
        }

        // 将排除的概率分配给未中奖
        noPrizeProb += totalExcludedProb;

        // 计算累积概率
        int cumulative = 0;

        cumulative += fullPackageProb;
        if (randomNum <= cumulative && fullPackageProb > 0) {
            return LotteryPrizeTypeEnum.FULL_PACKAGE;
        }

        cumulative += professionalReportProb;
        if (randomNum <= cumulative && professionalReportProb > 0) {
            return LotteryPrizeTypeEnum.PROFESSIONAL_REPORT;
        }

        cumulative += basicReportProb;
        if (randomNum <= cumulative && basicReportProb > 0) {
            return LotteryPrizeTypeEnum.BASIC_REPORT;
        }

        cumulative += askCountProb;
        if (randomNum <= cumulative && askCountProb > 0) {
            return LotteryPrizeTypeEnum.ASK_COUNT_5;
        }

        cumulative += contentMemberProb;
        if (randomNum <= cumulative && contentMemberProb > 0) {
            return LotteryPrizeTypeEnum.CONTENT_MEMBER_1DAY;
        }

        // 剩余概率为未中奖
        return LotteryPrizeTypeEnum.NO_PRIZE;
    }

    /**
     * 无专业版报告库存时的抽奖逻辑
     */
    private LotteryPrizeTypeEnum executeLotteryNoStock(int randomNum, List<Integer> wonPrizeTypes) {
        // 获取原始概率配置
        int fullPackageProb = getProbabilityConfig(CONFIG_KEY_FULL_PACKAGE_PROB_NO_STOCK, DEFAULT_FULL_PACKAGE_PROB_NO_STOCK);
        int basicReportProb = getProbabilityConfig(CONFIG_KEY_BASIC_REPORT_PROB_NO_STOCK, DEFAULT_BASIC_REPORT_PROB_NO_STOCK);
        int askCountProb = getProbabilityConfig(CONFIG_KEY_ASK_COUNT_PROB_NO_STOCK, DEFAULT_ASK_COUNT_PROB_NO_STOCK);
        int contentMemberProb = getProbabilityConfig(CONFIG_KEY_CONTENT_MEMBER_PROB_NO_STOCK, DEFAULT_CONTENT_MEMBER_PROB_NO_STOCK);
        int noPrizeProb = getProbabilityConfig(CONFIG_KEY_NO_PRIZE_PROB_NO_STOCK, DEFAULT_NO_PRIZE_PROB_NO_STOCK);

        // 排除已中过的奖励，重新分配概率
        int totalExcludedProb = 0;
        if (wonPrizeTypes.contains(LotteryPrizeTypeEnum.FULL_PACKAGE.getType())) {
            totalExcludedProb += fullPackageProb;
            fullPackageProb = 0;
        }
        if (wonPrizeTypes.contains(LotteryPrizeTypeEnum.BASIC_REPORT.getType())) {
            totalExcludedProb += basicReportProb;
            basicReportProb = 0;
        }
        if (wonPrizeTypes.contains(LotteryPrizeTypeEnum.ASK_COUNT_5.getType())) {
            totalExcludedProb += askCountProb;
            askCountProb = 0;
        }
        if (wonPrizeTypes.contains(LotteryPrizeTypeEnum.CONTENT_MEMBER_1DAY.getType())) {
            totalExcludedProb += contentMemberProb;
            contentMemberProb = 0;
        }

        // 将排除的概率分配给未中奖
        noPrizeProb += totalExcludedProb;

        // 计算累积概率
        int cumulative = 0;

        cumulative += fullPackageProb;
        if (randomNum <= cumulative && fullPackageProb > 0) {
            return LotteryPrizeTypeEnum.FULL_PACKAGE;
        }

        cumulative += basicReportProb;
        if (randomNum <= cumulative && basicReportProb > 0) {
            return LotteryPrizeTypeEnum.BASIC_REPORT;
        }

        cumulative += askCountProb;
        if (randomNum <= cumulative && askCountProb > 0) {
            return LotteryPrizeTypeEnum.ASK_COUNT_5;
        }

        cumulative += contentMemberProb;
        if (randomNum <= cumulative && contentMemberProb > 0) {
            return LotteryPrizeTypeEnum.CONTENT_MEMBER_1DAY;
        }

        // 剩余概率为未中奖
        return LotteryPrizeTypeEnum.NO_PRIZE;
    }

    /**
     * 检查专业版报告库存
     */
    private boolean checkProfessionalReportStock() {
        int dailyLimit = getProfessionalReportDailyLimit();
        
        LocalDateTime startOfDay = LocalDateTime.now().with(LocalTime.MIN);
        LocalDateTime endOfDay = LocalDateTime.now().with(LocalTime.MAX);
        Long todayCount = lotteryRecordMapper.countTodayPrizeByType(
                LotteryPrizeTypeEnum.PROFESSIONAL_REPORT.getType(), startOfDay, endOfDay);
        
        return todayCount < dailyLimit;
    }

    /**
     * 发放奖品
     */
    @Transactional(rollbackFor = Exception.class)
    public void awardPrize(Long userId, LotteryPrizeTypeEnum prizeType, Long recordId) {
        try {
            UserAssetsDO userAssets = userAssetsService.getUserAssetsByUserId(userId);
            if (userAssets == null) {
                log.warn("用户{}资产信息不存在，无法发放奖品", userId);
                return;
            }

            UserAssetsSaveReqVO updateReqVO = new UserAssetsSaveReqVO();
            updateReqVO.setId(userAssets.getId());

            switch (prizeType) {
                case BASIC_REPORT:
                    // 基础版报告一次
                    updateReqVO.setTrailCount((userAssets.getTrailCount() == null ? 0 : userAssets.getTrailCount()) + 1);
                    updateReqVO.setTrailLeftCount((userAssets.getTrailLeftCount() == null ? 0 : userAssets.getTrailLeftCount()) + 1);
                    // 同步到用户表
                    syncToUserTable(userId, "basic", 1);
                    break;
                case PROFESSIONAL_REPORT:
                    // 专业版报告一次
                    updateReqVO.setPsCount((userAssets.getPsCount() == null ? 0 : userAssets.getPsCount()) + 1);
                    updateReqVO.setPsLeftCount((userAssets.getPsLeftCount() == null ? 0 : userAssets.getPsLeftCount()) + 1);
                    // 同步到用户表
                    syncToUserTable(userId, "professional", 1);
                    break;
                case ASK_COUNT_5:
                    // 问答次数5次
                    updateReqVO.setAskCount((userAssets.getAskCount() == null ? 0 : userAssets.getAskCount()) + 5);
                    updateReqVO.setAskLeftCount((userAssets.getAskLeftCount() == null ? 0 : userAssets.getAskLeftCount()) + 5);
                    break;
                case CONTENT_MEMBER_1DAY:
                    // 内容会员1天
                    LocalDateTime now = LocalDateTime.now();
                    LocalDateTime endTime = userAssets.getContentEndTime();
                    if (endTime == null || endTime.isBefore(now)) {
                        // 如果没有会员或已过期，从现在开始计算
                        updateReqVO.setContentStartTime(now);
                        updateReqVO.setContentEndTime(now.plusDays(1));
                    } else {
                        // 如果还有有效会员，延长1天
                        updateReqVO.setContentEndTime(endTime.plusDays(1));
                    }
                    break;
                case FULL_PACKAGE:
                    // 全套奖励：包含所有奖项
                    awardFullPackage(userId, userAssets, updateReqVO);
                    break;
                default:
                    break;
            }

            // 更新用户资产
            userAssetsService.updateUserAssets(updateReqVO);

            // 更新抽奖记录为已发放
            LotteryRecordDO updateRecord = new LotteryRecordDO();
            updateRecord.setId(recordId);
            updateRecord.setAwarded(true);
            updateRecord.setAwardTime(LocalDateTime.now());
            updateRecord.setRemark("系统自动发放");
            lotteryRecordMapper.updateById(updateRecord);

            log.info("用户{}抽奖奖品{}发放成功", userId, prizeType.getName());
        } catch (Exception e) {
            log.error("用户{}抽奖奖品{}发放失败", userId, prizeType.getName(), e);
            throw e;
        }
    }

    /**
     * 发放全套奖励
     */
    private void awardFullPackage(Long userId, UserAssetsDO userAssets, UserAssetsSaveReqVO updateReqVO) {
        // 检查专业版报告是否还有库存
        boolean hasProfessionalReportStock = checkProfessionalReportStock();

        // 基础版报告一次
        updateReqVO.setTrailCount((userAssets.getTrailCount() == null ? 0 : userAssets.getTrailCount()) + 1);
        updateReqVO.setTrailLeftCount((userAssets.getTrailLeftCount() == null ? 0 : userAssets.getTrailLeftCount()) + 1);

        // 专业版报告一次（如果有库存）
        if (hasProfessionalReportStock) {
            updateReqVO.setPsCount((userAssets.getPsCount() == null ? 0 : userAssets.getPsCount()) + 1);
            updateReqVO.setPsLeftCount((userAssets.getPsLeftCount() == null ? 0 : userAssets.getPsLeftCount()) + 1);
        }

        // 问答次数5次
        updateReqVO.setAskCount((userAssets.getAskCount() == null ? 0 : userAssets.getAskCount()) + 5);
        updateReqVO.setAskLeftCount((userAssets.getAskLeftCount() == null ? 0 : userAssets.getAskLeftCount()) + 5);

        // 内容会员1天
        LocalDateTime now = LocalDateTime.now();
        LocalDateTime endTime = userAssets.getContentEndTime();
        if (endTime == null || endTime.isBefore(now)) {
            // 如果没有会员或已过期，从现在开始计算
            updateReqVO.setContentStartTime(now);
            updateReqVO.setContentEndTime(now.plusDays(1));
        } else {
            // 如果还有有效会员，延长1天
            updateReqVO.setContentEndTime(endTime.plusDays(1));
        }

        // 同步到用户表
        syncToUserTable(userId, "basic", 1);
        if (hasProfessionalReportStock) {
            syncToUserTable(userId, "professional", 1);
        }

        log.info("用户{}获得全套奖励，包含专业版报告: {}", userId, hasProfessionalReportStock);
    }

    /**
     * 同步到用户表
     */
    private void syncToUserTable(Long userId, String reportType, int count) {
        AdminUserDO user = adminUserMapper.selectById(userId);
        if (user != null) {
            AdminUserDO updateUser = new AdminUserDO();
            updateUser.setId(userId);
            
            if ("basic".equals(reportType)) {
                updateUser.setTestTotalTimes((user.getTestTotalTimes() == null ? 0 : user.getTestTotalTimes()) + count);
                updateUser.setTestLeftTimes((user.getTestLeftTimes() == null ? 0 : user.getTestLeftTimes()) + count);
            } else if ("professional".equals(reportType)) {
                updateUser.setProTotalTimes((user.getProTotalTimes() == null ? 0 : user.getProTotalTimes()) + count);
                updateUser.setProLeftTimes((user.getProLeftTimes() == null ? 0 : user.getProLeftTimes()) + count);
            }
            
            adminUserMapper.updateById(updateUser);
        }
    }

    /**
     * 获取每日抽奖次数限制
     */
    private int getDailyLotteryLimit() {
        LotteryConfigDO config = lotteryConfigMapper.selectByConfigKey(CONFIG_KEY_DAILY_LOTTERY_LIMIT);
        if (config != null) {
            try {
                return Integer.parseInt(config.getConfigValue());
            } catch (NumberFormatException e) {
                log.warn("抽奖配置{}值格式错误: {}", CONFIG_KEY_DAILY_LOTTERY_LIMIT, config.getConfigValue());
            }
        }
        return DEFAULT_DAILY_LOTTERY_LIMIT;
    }

    /**
     * 获取专业版报告每日限量
     */
    private int getProfessionalReportDailyLimit() {
        LotteryConfigDO config = lotteryConfigMapper.selectByConfigKey(CONFIG_KEY_PROFESSIONAL_REPORT_DAILY_LIMIT);
        if (config != null) {
            try {
                return Integer.parseInt(config.getConfigValue());
            } catch (NumberFormatException e) {
                log.warn("抽奖配置{}值格式错误: {}", CONFIG_KEY_PROFESSIONAL_REPORT_DAILY_LIMIT, config.getConfigValue());
            }
        }
        return DEFAULT_PROFESSIONAL_REPORT_DAILY_LIMIT;
    }

    /**
     * 获取概率配置
     */
    private int getProbabilityConfig(String configKey, int defaultValue) {
        LotteryConfigDO config = lotteryConfigMapper.selectByConfigKey(configKey);
        if (config != null) {
            try {
                int value = Integer.parseInt(config.getConfigValue());
                if (value >= 0 && value <= 100) {
                    return value;
                } else {
                    log.warn("抽奖概率配置{}值超出范围[0-100]: {}", configKey, config.getConfigValue());
                }
            } catch (NumberFormatException e) {
                log.warn("抽奖概率配置{}值格式错误: {}", configKey, config.getConfigValue());
            }
        }
        return defaultValue;
    }

    /**
     * 验证概率配置是否合理
     */
    private void validateProbabilityConfig() {
        // 验证有库存时的概率配置
        int totalWithStock = getProbabilityConfig(CONFIG_KEY_FULL_PACKAGE_PROB_WITH_STOCK, DEFAULT_FULL_PACKAGE_PROB_WITH_STOCK)
                + getProbabilityConfig(CONFIG_KEY_PROFESSIONAL_REPORT_PROB_WITH_STOCK, DEFAULT_PROFESSIONAL_REPORT_PROB_WITH_STOCK)
                + getProbabilityConfig(CONFIG_KEY_BASIC_REPORT_PROB_WITH_STOCK, DEFAULT_BASIC_REPORT_PROB_WITH_STOCK)
                + getProbabilityConfig(CONFIG_KEY_ASK_COUNT_PROB_WITH_STOCK, DEFAULT_ASK_COUNT_PROB_WITH_STOCK)
                + getProbabilityConfig(CONFIG_KEY_CONTENT_MEMBER_PROB_WITH_STOCK, DEFAULT_CONTENT_MEMBER_PROB_WITH_STOCK)
                + getProbabilityConfig(CONFIG_KEY_NO_PRIZE_PROB_WITH_STOCK, DEFAULT_NO_PRIZE_PROB_WITH_STOCK);

        if (totalWithStock != 100) {
            log.warn("有库存时概率配置总和不等于100%: {}", totalWithStock);
        }

        // 验证无库存时的概率配置
        int totalNoStock = getProbabilityConfig(CONFIG_KEY_FULL_PACKAGE_PROB_NO_STOCK, DEFAULT_FULL_PACKAGE_PROB_NO_STOCK)
                + getProbabilityConfig(CONFIG_KEY_BASIC_REPORT_PROB_NO_STOCK, DEFAULT_BASIC_REPORT_PROB_NO_STOCK)
                + getProbabilityConfig(CONFIG_KEY_ASK_COUNT_PROB_NO_STOCK, DEFAULT_ASK_COUNT_PROB_NO_STOCK)
                + getProbabilityConfig(CONFIG_KEY_CONTENT_MEMBER_PROB_NO_STOCK, DEFAULT_CONTENT_MEMBER_PROB_NO_STOCK)
                + getProbabilityConfig(CONFIG_KEY_NO_PRIZE_PROB_NO_STOCK, DEFAULT_NO_PRIZE_PROB_NO_STOCK);

        if (totalNoStock != 100) {
            log.warn("无库存时概率配置总和不等于100%: {}", totalNoStock);
        }
    }

    @Override
    public String getFullPackageDescription(boolean hasProfessionalReportStock) {
        StringBuilder description = new StringBuilder("包含：");
        description.append("基础版报告1次");

        if (hasProfessionalReportStock) {
            description.append("、专业版报告1次");
        }

        description.append("、问答次数5次、内容会员1天");

        if (!hasProfessionalReportStock) {
            description.append("（专业版报告今日已售完）");
        }

        return description.toString();
    }

    @Override
    public boolean completeShareTaskForLottery(Long userId) {
        return userTaskService.completeShareTask(userId);
    }

    @Override
    public boolean completeInviteFriendTaskForLottery(Long userId) {
        return userTaskService.completeInviteFriendTask(userId);
    }

    @Override
    public boolean completeProfileTaskForLottery(Long userId) {
        return userTaskService.completeProfileTask(userId);
    }
}
